<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/%E6%AD%A6%E6%B1%8932x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/%E6%AD%A6%E6%B1%8916x16.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib1/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="/lib1/pace/pace-theme-center-simple.min.css">
  <script src="/lib1/pace/pace.min.js"></script>

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"example.com","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="MobxMobX 是一个经过战火洗礼的库，它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。MobX背后的哲学很简单: 任何源自应用状态的东西都应该自动地获得。 其中包括UI、数据序列化、服务器通讯，等等。 React 和 MobX 是一对强力组合。React 通过提">
<meta property="og:type" content="article">
<meta property="og:title" content="Mobx入门">
<meta property="og:url" content="http://example.com/2021/11/30/%E7%9B%92%E9%A9%AC%E6%8A%80%E6%9C%AF%E6%A0%88%E5%88%9D%E5%AD%A6/Mobx%E5%85%A5%E9%97%A8/index.html">
<meta property="og:site_name" content="Technological Blog">
<meta property="og:description" content="MobxMobX 是一个经过战火洗礼的库，它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。MobX背后的哲学很简单: 任何源自应用状态的东西都应该自动地获得。 其中包括UI、数据序列化、服务器通讯，等等。 React 和 MobX 是一对强力组合。React 通过提">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://example.com/image/Mobx%E5%85%A5%E9%97%A8/flow.png">
<meta property="og:image" content="http://example.com/image/Mobx%E5%85%A5%E9%97%A8/action-state-view.png">
<meta property="article:published_time" content="2021-11-30T04:18:39.000Z">
<meta property="article:modified_time" content="2021-11-24T13:25:24.073Z">
<meta property="article:author" content="Li Yudong">
<meta property="article:tag" content="公司技术栈">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://example.com/image/Mobx%E5%85%A5%E9%97%A8/flow.png">

<link rel="canonical" href="http://example.com/2021/11/30/%E7%9B%92%E9%A9%AC%E6%8A%80%E6%9C%AF%E6%A0%88%E5%88%9D%E5%AD%A6/Mobx%E5%85%A5%E9%97%A8/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>Mobx入门 | Technological Blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Technological Blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">IT小白的成长之旅</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="tags fa-fw"></i>标签<span class="badge">18</span></a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="th fa-fw"></i>分类<span class="badge">14</span></a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="archive fa-fw"></i>归档<span class="badge">95</span></a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <a href="https://github.com/tiarmor1" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/11/30/%E7%9B%92%E9%A9%AC%E6%8A%80%E6%9C%AF%E6%A0%88%E5%88%9D%E5%AD%A6/Mobx%E5%85%A5%E9%97%A8/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/author.jpg">
      <meta itemprop="name" content="Li Yudong">
      <meta itemprop="description" content="">
    </span>
    
    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Technological Blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Mobx入门
        </h1>
    
        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
    
              <time title="创建时间：2021-11-30 12:18:39" itemprop="dateCreated datePublished" datetime="2021-11-30T12:18:39+08:00">2021-11-30</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-11-24 21:25:24" itemprop="dateModified" datetime="2021-11-24T21:25:24+08:00">2021-11-24</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E7%9B%92%E9%A9%AC%E6%8A%80%E6%9C%AF%E6%A0%88/" itemprop="url" rel="index"><span itemprop="name">盒马技术栈</span></a>
                </span>
            </span>
    
          
    
        </div>
      </header>
    
    
    
    
    <div class="post-body" itemprop="articleBody">
    
      
        <h1 id="Mobx"><a href="#Mobx" class="headerlink" title="Mobx"></a>Mobx</h1><p>MobX 是一个经过战火洗礼的库，它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。MobX背后的哲学很简单:</p>
<p><em>任何源自应用状态的东西都应该自动地获得。</em></p>
<p>其中包括UI、数据序列化、服务器通讯，等等。</p>
<p>React 和 MobX 是一对强力组合。React 通过提供机制把应用状态转换为可渲染组件树并对其进行渲染。而MobX提供机制来存储和更新应用状态供 React 使用。</p>
<p>对于应用开发中的常见问题，React 和 MobX 都提供了最优和独特的解决方案。React 提供了优化UI渲染的机制， 这种机制就是通过使用虚拟DOM来减少昂贵的DOM变化的数量。MobX 提供了优化应用状态与 React 组件同步的机制，这种机制就是使用响应式虚拟依赖状态图表，它只有在真正需要的时候才更新并且永远保持是最新的。</p>
<p><img src="/../../image/Mobx%E5%85%A5%E9%97%A8/flow.png" alt="MobX unidirectional flow"></p>
<h2 id="核心概念"><a href="#核心概念" class="headerlink" title="核心概念"></a>核心概念</h2><h3 id="Observable-state"><a href="#Observable-state" class="headerlink" title="Observable state"></a>Observable state</h3><p>可观察的状态：MobX 为现有的数据结构(如对象，数组和类实例)添加了可观察的功能。 通过使用 <a href="http://cn.mobx.js.org/refguide/observable-decorator.html" target="_blank" rel="noopener">@observable</a> 装饰器(ES.Next)来给你的类属性添加注解就可以简单地完成这一切。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; observable &#125; <span class="keyword">from</span> <span class="string">"mobx"</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Todo</span> </span>&#123;</span><br><span class="line">    id = <span class="built_in">Math</span>.random();</span><br><span class="line">    @observable title = <span class="string">""</span>;</span><br><span class="line">    @observable finished = <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用 <code>observable</code> 很像把对象的属性变成excel的单元格。 但和单元格不同的是，这些值不只是原始值，还可以是引用值，比如对象和数组。如果你的环境不支持装饰器语法，也不必担心。 你可以点击<a href="https://cn.mobx.js.org/best/decorators.html" target="_blank" rel="noopener">这里</a>查看如何进行设置。 或者你可以直接跳过设置，因为 MobX 可以通过 <em>decorate</em> 工具在不支持装饰器语法的情况加使用。 尽管如此，多数 MobX 用户更喜欢装饰器语法，因为它更简洁。</p>
<p>例如，上面一段代码的ES5版本应该是这样:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; decorate, observable &#125; <span class="keyword">from</span> <span class="string">"mobx"</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Todo</span> </span>&#123;</span><br><span class="line">    id = <span class="built_in">Math</span>.random();</span><br><span class="line">    title = <span class="string">""</span>;</span><br><span class="line">    finished = <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line">decorate(Todo, &#123;</span><br><span class="line">    title: observable,</span><br><span class="line">    finished: observable</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h3 id="Computed-values"><a href="#Computed-values" class="headerlink" title="Computed values"></a>Computed values</h3><p>计算值：使用 MobX， 你可以定义在相关数据发生变化时自动更新的值。 通过<a href="http://cn.mobx.js.org/refguide/computed-decorator.html" target="_blank" rel="noopener"><code>@computed</code></a> 装饰器或者利用 <code>(extend)Observable</code> 时调用 的getter / setter 函数来进行使用。(当然，这里也可以再次使用 <code>decorate</code> 来替代 <code>@</code> 语法)。</p>
<p>其实在逻辑上很像Vue的双向绑定思维。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TodoList</span> </span>&#123;</span><br><span class="line">    @observable todos = [];</span><br><span class="line">    @computed <span class="keyword">get</span> unfinishedTodoCount() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.todos.filter(<span class="function"><span class="params">todo</span> =&gt;</span> !todo.finished).length;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>当添加了一个新的todo或者某个todo的 <code>finished</code> 属性发生变化时，MobX 会确保 <code>unfinishedTodoCount</code> 自动更新。 像这样的计算可以类似于 MS Excel 这样电子表格程序中的公式。每当只有在需要它们的时候，它们才会自动更新。</p>
<h3 id="Reactions"><a href="#Reactions" class="headerlink" title="Reactions"></a>Reactions</h3><p>反应：Reactions 和计算值很像，但它不是产生一个新的值，而是会产生一些副作用，比如打印到控制台、网络请求、递增地更新 React 组件树以修补DOM、等等。 简而言之，reactions 在 <a href="https://en.wikipedia.org/wiki/Reactive_programming" target="_blank" rel="noopener">响应式编程</a>和<a href="https://en.wikipedia.org/wiki/Imperative_programming" target="_blank" rel="noopener">命令式编程</a>之间建立沟通的桥梁。</p>
<p><em>MobX 会对在执行跟踪函数期间读取的任何现有的可观察属性做出反应</em>。</p>
<h4 id="React-组件"><a href="#React-组件" class="headerlink" title="React 组件"></a>React 组件</h4><p>如果你用 React 的话，可以把你的(无状态函数)组件变成响应式组件，方法是在组件上添加 <a href="http://cn.mobx.js.org/refguide/observable-decorator.html" target="_blank" rel="noopener"><code>observer</code></a> 函数/ 装饰器. <code>observer</code>由 <code>mobx-react</code> 包提供的。</p>
<figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123;Component&#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> ReactDOM <span class="keyword">from</span> <span class="string">'react-dom'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123;observer&#125; <span class="keyword">from</span> <span class="string">'mobx-react'</span>;</span><br><span class="line"></span><br><span class="line">@observer</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TodoListView</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line">            &lt;ul&gt;</span><br><span class="line">                &#123;this.props.todoList.todos.map(todo =&gt;</span><br><span class="line">                    &lt;TodoView todo=&#123;todo&#125; key=&#123;todo.id&#125; /&gt;</span><br><span class="line">                )&#125;</span><br><span class="line"><span class="xml">            <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span></span><br><span class="line"><span class="xml">            Tasks left: &#123;this.props.todoList.unfinishedTodoCount&#125;</span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> TodoView = observer(<span class="function">(<span class="params">&#123;todo&#125;</span>) =&gt;</span></span><br><span class="line">    &lt;li&gt;</span><br><span class="line">        &lt;input</span><br><span class="line">            type=<span class="string">"checkbox"</span></span><br><span class="line">            checked=&#123;todo.finished&#125;</span><br><span class="line">            onClick=&#123;() =&gt; todo.finished = !todo.finished&#125;</span><br><span class="line">        /&gt;&#123;todo.title&#125;</span><br><span class="line">    &lt;<span class="regexp">/li&gt;</span></span><br><span class="line"><span class="regexp">)</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">const store = new TodoList();</span></span><br><span class="line"><span class="regexp">ReactDOM.render(&lt;TodoListView todoList=&#123;store&#125; /</span>&gt;, <span class="built_in">document</span>.getElementById(<span class="string">'mount'</span>));</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><code>observer</code> 会将 React (函数)组件转换为它们需要渲染的数据的衍生。 使用 MobX 时没有所谓的智能和无脑组件。 所有的组件都会以巧妙的方式进行渲染，而只需要一种简单无脑的方式来定义它们。MobX会确保组件总是在需要的时重新渲染，但仅此而已。所以上面例子中的 <code>onClick</code> 处理方法会强制对应的 <code>TodoView</code> 进行渲染，如果未完成任务的数量(unfinishedTodoCount)已经改变，它将导致 <code>TodoListView</code> 进行渲染。 可是，如果移除 <code>Tasks left</code> 这行代码(或者将它放到另一个组件中)，当点击 <code>checkbox</code> 的时候 <code>TodoListView</code> 就不再重新渲染。你可以在 <a href="https://jsfiddle.net/mweststrate/wv3yopo0/" target="_blank" rel="noopener">JSFiddle</a> 中自己动手来验证这点。</p>
<h4 id="自定义-reactions"><a href="#自定义-reactions" class="headerlink" title="自定义 reactions"></a>自定义 reactions</h4><p>使用<a href="http://cn.mobx.js.org/refguide/autorun.html" target="_blank" rel="noopener"><code>autorun</code></a>、<a href="http://cn.mobx.js.org/refguide/reaction.html" target="_blank" rel="noopener"><code>reaction</code></a> 和 <a href="http://cn.mobx.js.org/refguide/when.html" target="_blank" rel="noopener"><code>when</code></a> 函数即可简单的创建自定义 reactions，以满足你的具体场景。</p>
<p>例如，每当 <code>unfinishedTodoCount</code> 的数量发生变化时，下面的 <code>autorun</code> 会打印日志消息:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">autorun(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Tasks left: "</span> + todos.unfinishedTodoCount)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h3 id="Actions"><a href="#Actions" class="headerlink" title="Actions"></a>Actions</h3><p>动作：不同于 flux 系的一些框架，MobX 对于如何处理用户事件是完全开明的。</p>
<ul>
<li>可以用类似 Flux 的方式完成</li>
<li>或者使用 RxJS 来处理事件</li>
<li>或者用最直观、最简单的方式来处理事件，正如上面演示所用的 <code>onClick</code></li>
</ul>
<p>最后全部归纳为: 状态应该以某种方式来更新。</p>
<p>当状态更新后，<code>MobX</code> 会以一种高效且无障碍的方式处理好剩下的事情。像下面如此简单的语句，已经足够用来自动更新用户界面了。</p>
<p>从技术上层面来讲，并不需要触发事件、调用分派程序或者类似的工作。归根究底 React 组件只是状态的华丽展示，而状态的衍生由 MobX 来管理。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">store.todos.push(</span><br><span class="line">    <span class="keyword">new</span> Todo(<span class="string">"Get Coffee"</span>),</span><br><span class="line">    <span class="keyword">new</span> Todo(<span class="string">"Write simpler code"</span>)</span><br><span class="line">);</span><br><span class="line">store.todos[<span class="number">0</span>].finished = <span class="literal">true</span>;</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p>尽管如此，MobX 还是提供了 <a href="http://cn.mobx.js.org/refguide/action.html" target="_blank" rel="noopener"><code>actions</code></a> 这个可选的内置概念。 如果你现在就想要了解如何编写 actions，请阅读 Actions 章节。很简单！ 使用 <code>actions</code> 是有优势的: 它们可以帮助你把代码组织的更好，还能在状态何时何地应该被修改这个问题上帮助你做出明智的决定。</p>
<h3 id="简单可扩展"><a href="#简单可扩展" class="headerlink" title="简单可扩展"></a>简单可扩展</h3><p>MobX 是状态管理库中侵入性最小的之一。这使得 <code>MobX</code>的方法不但简单，而且可扩展性也非常好:</p>
<p>使用类和真正的引用：</p>
<p>使用 MobX 不需要使数据标准化。这使得库十分适合那些异常复杂的领域模型(以 Mendix 为例: 一个应用中有大约500个领域类)。</p>
<p>保证参照完整性：</p>
<p>因为数据不需要标准化，所以 MobX 会自动跟踪状态和衍生之间的关系，你可以免费获得参照完整性。渲染通过三级间接寻址访问的数据？</p>
<p>没有问题，MobX 会跟踪它们，一旦其中一个引用发生了变化，就会重新渲染。作为回报，陈年的老bug已不复存在。作为一个程序员，你可能记不住修改的一些数据可能会影响到的某个角落里看起来毫不相关的组件，但 MobX 不会。</p>
<p>更简单的 actions 更便于维护：</p>
<p>正如上面所演示的，使用 MobX 修改状态是非常简单的。你只需简单的写出你的目的。MobX 会替你处理好剩下的事情。</p>
<p>细粒度的可观测性是高效的：</p>
<p>MobX 构建应用中所有衍生的图形，以找到保持最新状态所需的重新计算的最少次数。“衍生一切”或许听上去开销很昂贵，但 MobX 构建虚拟衍生图以保持衍生与状态同步所需的重计算的数量最小化。</p>
<p>事实上，在 Mendix 测试 MobX 时我们发现使用这个库跟踪代码中的关系通常会更有效，而不是通过使用手写事件或基于容器组件的“智能”选择器来推送更改。</p>
<p>简单来说，是因为 MobX 会在数据上建立更细粒度的“监听器”，而不是通过程序来控制。</p>
<p>其次, MobX 看到衍生之间的因果关系，因此它可以为衍生排序，使得衍生不会运行多次或引入缺陷。</p>
<p>想了解这是如何工作的？ 请参见 <a href="https://medium.com/@mweststrate/becoming-fully-reactive-an-in-depth-explanation-of-mobservable-55995262a254" target="_blank" rel="noopener">深入剖析 MobX</a>。</p>
<p>易操作性：</p>
<p>MobX 使用原生 javascript 。由于它的侵入性不强，它可以和绝大部分 javascript 库共同使用，而不需要特定的 MobX 风格库。</p>
<p>所以你可以继续使用你的路由，数据获取和工具库，比如<code>react-router</code>、 <code>director</code>、 <code>superagent</code>、 <code>lodash</code>，等等。</p>
<p>出于同样的原因，你可以在服务器端和客户端使用它，也可以在 react-native 这样的同构应用中使用。</p>
<p>结论就是: 相比其它状态管理解决方案，当使用 MobX 时通常只需学习更少的新概念。</p>
<p>赞誉：</p>
<p>MobX 的灵感来自excel表格中的反应式编程原理。同样也受到像 MeteorJS、knockout和Vue.js这样的 MVVM 框架的启发。但是 MobX 把透明的函数响应式编程(Transparent Functional Reactive Programming)提升到了一个更好的水平并且提供了独立的实现。它以一种无障碍、同步、可预见和高效的方式实现了 TFRP。</p>
<h2 id="Mobx要点"><a href="#Mobx要点" class="headerlink" title="Mobx要点"></a>Mobx要点</h2><h3 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h3><p>使用 MobX 将一个应用变成响应式的可归纳为以下三个步骤:</p>
<ol>
<li>定义状态并使其可观察</li>
</ol>
<p>可以用任何你喜欢的数据结构来存储状态，如对象、数组、类。 循环数据结构、引用，都没有关系。 只要确保所有会随时间流逝而改变的属性打上 <code>mobx</code> 的标记使它们变得可观察即可。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;observable&#125; <span class="keyword">from</span> <span class="string">'mobx'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> appState = observable(&#123;</span><br><span class="line">    timer: <span class="number">0</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>创建视图以响应状态的变化</li>
</ol>
<p>我们的 <code>appState</code> 还没有观察到任何的东西。 你可以创建视图，当 <code>appState</code> 中相关数据发生改变时视图会自动更新。 MobX 会以一种最小限度的方式来更新视图。 事实上这一点可以节省了你大量的样板文件，并且它有着<a href="https://mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/" target="_blank" rel="noopener">令人匪夷所思的高效</a>。</p>
<p>通常来说，任何函数都可以成为可以观察自身数据的响应式视图，MobX 可以在任何符合ES5的JavaScript环境中应用。 但是在这所用的示例是 ES6版本的 React 组件视图。</p>
<figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;observer&#125; <span class="keyword">from</span> <span class="string">'mobx-react'</span>;</span><br><span class="line"></span><br><span class="line">@observer</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TimerView</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            &lt;button onClick=&#123;<span class="keyword">this</span>.onReset.bind(<span class="keyword">this</span>)&#125;&gt;</span><br><span class="line">                Seconds passed: &#123;<span class="keyword">this</span>.props.appState.timer&#125;</span><br><span class="line">            &lt;<span class="regexp">/button&gt;</span></span><br><span class="line"><span class="regexp">        );</span></span><br><span class="line"><span class="regexp">    &#125;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">    onReset() &#123;</span></span><br><span class="line"><span class="regexp">        this.props.appState.resetTimer();</span></span><br><span class="line"><span class="regexp">    &#125;</span></span><br><span class="line"><span class="regexp">&#125;;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">ReactDOM.render(&lt;TimerView appState=&#123;appState&#125; /</span>&gt;, <span class="built_in">document</span>.body);</span><br></pre></td></tr></table></figure>

<ol start="3">
<li>更改状态</li>
</ol>
<p>第三件要做的事就是更改状态。 也就是你的应用究竟要做什么。 不像一些其它框架，MobX 不会命令你如何如何去做。 这是最佳实践，但关键要记住一点: ***MobX 帮助你以一种简单直观的方式来完成工作***。</p>
<p>下面的代码每秒都会修改你的数据，而当需要的时候UI会自动更新。 无论是在<strong>改变</strong>状态的控制器函数中，还是在应该<strong>更新</strong>的视图中，都没有明确的关系定义。 使用 <code>observable</code> 来装饰你的<strong>状态</strong>和<strong>视图</strong>，这足以让 MobX检测所有关系了。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">appState.resetTimer = action(<span class="function"><span class="keyword">function</span> <span class="title">reset</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    appState.timer = <span class="number">0</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">setInterval(action(<span class="function"><span class="keyword">function</span> <span class="title">tick</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    appState.timer += <span class="number">1</span>;</span><br><span class="line">&#125;), <span class="number">1000</span>);</span><br></pre></td></tr></table></figure>

<p>只有在严格模式(默认是不启用)下使用 MobX 时才需要 <code>action</code> 包装。 建议使用 action，因为它将帮助你更好地组织应用，并表达出一个函数修改状态的意图。 同时,它还自动应用事务以获得最佳性能。</p>
<p>可以通过 <a href="http://jsfiddle.net/mweststrate/wgbe4guu/" target="_blank" rel="noopener">JSFiddle</a> 或者克隆 <a href="https://github.com/mobxjs/mobx-react-boilerplate" target="_blank" rel="noopener">MobX 样板工程</a> 来随意试用这个示例。</p>
<h3 id="概念与原则"><a href="#概念与原则" class="headerlink" title="概念与原则"></a>概念与原则</h3><h4 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h4><p>MobX 区分了以下几个应用中的概念。 在之前的要点中已经见过了，现在让我们更深入地了解它们。</p>
<ol>
<li>State(状态)</li>
</ol>
<p><strong>状态</strong> 是驱动应用的数据。 通常有像待办事项列表这样的<strong>领域特定状态</strong>，还有像当前已选元素的<strong>视图状态</strong>。 记住，状态就像是有数据的excel表格。</p>
<ol start="2">
<li>Derivations(衍生)</li>
</ol>
<p><strong>任何</strong> 源自<strong>状态</strong>并且不会再有任何进一步的相互作用的东西就是衍生。 衍生以多种形式存在:</p>
<ul>
<li><strong>用户界面</strong></li>
<li><strong>衍生数据</strong>，比如剩下的待办事项的数量。</li>
<li><strong>后端集成</strong>，比如把变化发送到服务器端。</li>
</ul>
<p>MobX 区分了两种类型的衍生:</p>
<ul>
<li><strong>Computed values(计算值)</strong> - 它们是永远可以使用纯函数(pure function)从当前可观察状态中衍生出的值。</li>
<li><strong>Reactions(反应)</strong> - Reactions 是当状态改变时需要自动发生的副作用。需要有一个桥梁来连接命令式编程(imperative programming)和响应式编程(reactive programming)。或者说得更明确一些，它们最终都需要实现I / O 操作。</li>
</ul>
<p>刚开始使用 MobX 时，人们倾向于频繁的使用 reactions。 黄金法则: 如果你想创建一个基于当前状态的值时，请使用 <code>computed</code>。</p>
<p>回到excel表格这个比喻中来，公式是<strong>计算</strong>值的衍生。但对于用户来说，能看到屏幕给出的<strong>反应</strong>则需要部分重绘GUI。</p>
<ol start="3">
<li>Actions(动作)</li>
</ol>
<p><strong>动作</strong> 是任一一段可以改变<strong>状态</strong>的代码。用户事件、后端数据推送、预定事件、等等。 动作类似于用户在excel单元格中输入一个新的值。</p>
<p>在 MobX 中可以显式地定义动作，它可以帮你把代码组织的更清晰。 如果是在<a href="https://cn.mobx.js.org/refguide/api#-enforceactions" target="_blank" rel="noopener"><strong>严格模式</strong></a>下使用 MobX的话，MobX 会强制只有在动作之中才可以修改状态。</p>
<h4 id="原则"><a href="#原则" class="headerlink" title="原则"></a>原则</h4><p>MobX 支持单向数据流，也就是<strong>动作</strong>改变<strong>状态</strong>，而状态的改变会更新所有受影响的<strong>视图</strong>。</p>
<p><img src="/../../image/Mobx%E5%85%A5%E9%97%A8/action-state-view.png" alt="Action, State, View"></p>
<p>当<strong>状态</strong>改变时，所有<strong>衍生</strong>都会进行<strong>原子级的自动</strong>更新。因此永远不可能观察到中间值。</p>
<p>所有<strong>衍生</strong>默认都是<strong>同步</strong>更新。这意味着例如<strong>动作</strong>可以在改变<strong>状态</strong>之后直接可以安全地检查计算值。</p>
<p><strong>计算值</strong> 是<strong>延迟</strong>更新的。任何不在使用状态的计算值将不会更新，直到需要它进行副作用（I / O）操作时。 如果视图不再使用，那么它会自动被垃圾回收。</p>
<p>所有的<strong>计算值</strong>都应该是<strong>纯净</strong>的。它们不应该用来改变<strong>状态</strong>。</p>
<h4 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h4><p>下面的代码清单举例说明了以上的概念和原则:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;observable, autorun&#125; <span class="keyword">from</span> <span class="string">'mobx'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> todoStore = observable(&#123;</span><br><span class="line">    <span class="comment">/* 一些观察的状态 */</span></span><br><span class="line">    todos: [],</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 推导值 */</span></span><br><span class="line">    <span class="keyword">get</span> completedCount() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.todos.filter(<span class="function"><span class="params">todo</span> =&gt;</span> todo.completed).length;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 观察状态改变的函数 */</span></span><br><span class="line">autorun(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Completed %d of %d items"</span>,</span><br><span class="line">        todoStore.completedCount,</span><br><span class="line">        todoStore.todos.length</span><br><span class="line">    );</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ..以及一些改变状态的动作 */</span></span><br><span class="line">todoStore.todos[<span class="number">0</span>] = &#123;</span><br><span class="line">    title: <span class="string">"Take a walk"</span>,</span><br><span class="line">    completed: <span class="literal">false</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// -&gt; 同步打印 'Completed 0 of 1 items'</span></span><br><span class="line"></span><br><span class="line">todoStore.todos[<span class="number">0</span>].completed = <span class="literal">true</span>;</span><br><span class="line"><span class="comment">// -&gt; 同步打印 'Completed 1 of 1 items'</span></span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p>在<a href="https://mobxjs.github.io/mobx/getting-started.html" target="_blank" rel="noopener">10分钟入门 MobX 和 React</a>中你可以深入本示例并且围绕它使用 <a href="https://facebook.github.io/react/" target="_blank" rel="noopener">React</a> 来构建用户页面。</p>
<h1 id="API"><a href="#API" class="headerlink" title="API"></a>API</h1><h2 id="核心API"><a href="#核心API" class="headerlink" title="核心API"></a>核心API</h2><p>这里都是 MobX 中最重要的 API 。</p>
<blockquote>
<p>理解了<code>observable</code>、 <code>computed</code>、 <code>reactions</code> 和 <code>actions</code>的话，说明对于 Mobx 已经足够精通了,在你的应用中使用它</p>
</blockquote>
<h3 id="创建-observables"><a href="#创建-observables" class="headerlink" title="创建 observables"></a>创建 observables</h3><p><code>observable(value)</code></p>
<p>用法:</p>
<ul>
<li><code>observable(value)</code></li>
<li><code>@observable classProperty = value</code></li>
</ul>
<p>Observable 值可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射。</p>
<p><strong>注意:</strong> <code>observable(value)</code> 是一个便捷的 API ，此 API 只有在它可以被制作成可观察的数据结构(数组、映射或 observable 对象)时才会成功。对于所有其他值，不会执行转换。</p>
<p>匹配类型应用了以下转换规则，但可以通过使用 <a href="https://cn.mobx.js.org/refguide/api.html#decorators" target="_blank" rel="noopener"><em>装饰器</em></a> 进行微调。请参见下文。</p>
<ol>
<li><p>如果 <strong>value</strong> 是<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map" target="_blank" rel="noopener">ES6 Map</a>的实例: 会返回一个新的 <a href="https://cn.mobx.js.org/refguide/map.html" target="_blank" rel="noopener">Observable Map</a>。如果你不只关注某个特定entry的更改，而且对添加或删除其他entry时也做出反应的话，那么 Observable map 会非常有用。</p>
</li>
<li><p>如果 <strong>value</strong> 是数组，会返回一个 <a href="https://cn.mobx.js.org/refguide/array.html" target="_blank" rel="noopener">Observable Array</a>。</p>
</li>
<li><p>如果 <strong>value</strong> 是没有原型的对象或它的原型是 <code>Object.prototype</code>，那么对象会被克隆并且所有的属性都会被转换成可观察的。参见 <a href="https://cn.mobx.js.org/refguide/object.html" target="_blank" rel="noopener">Observable Object</a>。</p>
</li>
<li><p>如果value是有原型的对象，JavaSript 原始数据类型或者函数，值不会发生变化。如果你需要Boxed Observable，你可以采用下列任意方式:</p>
<ul>
<li>显式地调用 <code>observable.box(value)</code></li>
</ul>
</li>
</ol>
<ul>
<li>在类定义时使用 <code>@observable</code><ul>
<li>调用 <a href="https://cn.mobx.js.org/refguide/api.html#decorate" target="_blank" rel="noopener"><code>decorate()</code></a></li>
</ul>
</li>
<li>在类中使用 <code>extendObservable()</code> 来引入属性</li>
</ul>
<p>MobX 不会自动带有原型的对象转变成 observable，因为那是 observable 构造函数的职责。在构造函数中使用 <code>extendObservable</code> 或在类定义是使用 <code>@observable</code> 进行替代。</p>
<p>乍看之下，这些规则可能看上去很复杂，但实际上实践当中你会发现他们是非常直观的。</p>
<p>一些建议:</p>
<ul>
<li>要想使用 <code>@observable</code> 装饰器，首先要确保 在你的编译器(babel 或者 typescript)中 <a href="http://mobxjs.github.io/mobx/refguide/observable-decorator.html" target="_blank" rel="noopener">装饰器是启用的</a>。</li>
<li>默认情况下将一个数据结构转换成可观察的是<strong>有感染性的</strong>，这意味着 <code>observable</code> 被自动应用于数据结构包含的任何值，或者将来会被该数据结构包含的值。这个行为可以通过使用 <a href="https://cn.mobx.js.org/refguide/api.html#decorators" target="_blank" rel="noopener"><em>装饰器</em></a> 来更改。</li>
<li><em>[MobX 4 及以下版本]</em> 要创建键是动态的对象时永远都使用 maps！对象上只有初始化时便存在的属性会转换成可观察的，尽管新添加的属性可以通过使用 <code>extendObservable</code> 转换成可观察的。</li>
</ul>
<p><a href="https://cn.mobx.js.org/refguide/observable.html" target="_blank" rel="noopener">«<code>observable</code>»</a> — <a href="https://cn.mobx.js.org/refguide/observable-decorator.html" target="_blank" rel="noopener">«<code>@observable</code>»</a></p>
<p><code>@observable property = value</code></p>
<p><code>observable</code> 也可以用作属性的装饰器。它需要<a href="https://cn.mobx.js.org/best/decorators.html" target="_blank" rel="noopener">启用装饰器</a>而且它是 <code>extendObservable(this, { property: value })</code> 的语法糖。</p>
<p><a href="https://cn.mobx.js.org/refguide/observable-decorator.html" target="_blank" rel="noopener">«<code>详情</code>»</a></p>
<p><code>observable.box(value, options?)</code></p>
<p>创建一个 observable 的盒子，它用来存储value的 observable 引用。使用 <code>get()</code> 方法可以得到盒子中的当前value，而使用 <code>set()</code> 方法可以更新value。 这是所有其它 observable 创建的基础，但实际中你其实很少能使用到它。</p>
<p>通常盒子会自动地尝试把任何还不是 observable 的新值转换成 observable 。使用 <code>{deep: false}</code> 选项会禁用这项行为。</p>
<p><a href="https://cn.mobx.js.org/refguide/boxed.html" target="_blank" rel="noopener">«<code>详情</code>»</a></p>
<p><code>observable.object(value, decorators?, options?)</code></p>
<p>为提供的对象创建一个克隆并将其所有的属性转换成 observable 。 默认情况下这些属性中的任何值都会转换成 observable，但当使用 <code>{deep: false}</code> 选项时只有属性会转换成 observable 引用，而值不会改变(这也适用于将来分配的任何值)。</p>
<p><code>observable.object()</code> 的第二个参数可以很好地调整 <a href="https://cn.mobx.js.org/refguide/api.html#decorators" target="_blank" rel="noopener">装饰器</a> 的可观察性。</p>
<p><a href="https://cn.mobx.js.org/refguide/object.html" target="_blank" rel="noopener">«<code>详情</code>»</a></p>
<p><code>observable.array(value, options?)</code></p>
<p>基于提供的值来创建一个新的 observable 数组。</p>
<p>如果不想数组中的值转换成 observable 请使用 <code>{deep: false}</code> 选项。</p>
<p><a href="https://cn.mobx.js.org/refguide/array.html" target="_blank" rel="noopener">«<code>详情</code>»</a></p>
<p><code>observable.map(value, options?)</code></p>
<p>基于提供的值来创建一个新的 observable 映射。如果不想映射中的值转换成 observable 请使用 <code>{deep: false}</code> 选项。 当想创建动态的键集合并且需要能观察到键的添加和移除时，请使用 <code>map</code>。 因为内部使用了成熟的 <em>ES6 Map</em> ，你可以自由使用任何键而<strong>无需局限</strong>于字符串。</p>
<p><a href="https://cn.mobx.js.org/refguide/map.html" target="_blank" rel="noopener">«<code>详情</code>»</a></p>
<p><code>extendObservable</code></p>
<p>用法: <code>extendObservable(target, properties, decorators?, options?)</code></p>
<p>对于 <code>propertyMap</code> 中的每个键值对，都会作为一个(新)的 observable 属性引入到 target 对象中。 还可以在构造函数中使用来引入 observable 属性，这样就不需要用装饰器了。 如果 <code>propertyMap</code> 的某个值是一个 getter 函数，那么会引入一个<strong>computed</strong>属性。</p>
<p>如果新的属性不应该具备感染性(即新分配的值不应该自动地转换成 observable)的话，请使用 <code>extendObservable(target, props, decorators?, {deep: false})</code> 。 注意 <code>extendObservable</code> 增强了现有的对象，不像 <code>observable.object</code> 是创建一个新对象。</p>
<p><a href="https://cn.mobx.js.org/refguide/extend-observable.html" target="_blank" rel="noopener">«详情»</a></p>
<h3 id="装饰器-Decorators"><a href="#装饰器-Decorators" class="headerlink" title="装饰器(Decorators)"></a>装饰器(Decorators)</h3><p>使用装饰器可以很好地调节通过 <code>observable</code>、 <code>extendObservable</code> 和 <code>observable.object</code> 定义的属性的可观察性。它们还可以控制特定属性的自动转换规则。</p>
<p>可用的装饰器列表:</p>
<ul>
<li><strong><code>observable.deep</code></strong>: 所有 observable 都使用的默认的装饰器。它可以把任何指定的、非原始数据类型的、非 observable 的值转换成 observable。</li>
<li><strong><code>observable.ref</code></strong>: 禁用自动的 observable 转换，只是创建一个 observable 引用。</li>
<li><strong><code>observable.shallow</code></strong>: 只能与集合组合使用。 将任何分配的集合转换为浅 observable (而不是深 observable)的集合。 换句话说, 集合中的值将不会自动变为 observable。</li>
<li><strong><code>computed</code></strong>: 创建一个衍生属性, 参见 <a href="https://cn.mobx.js.org/refguide/computed-decorator.html" target="_blank" rel="noopener"><code>computed</code></a></li>
<li><strong><code>action</code></strong>: 创建一个动作, 参见 <a href="https://cn.mobx.js.org/refguide/action.html" target="_blank" rel="noopener"><code>action</code></a></li>
<li><strong><code>action.bound</code></strong>: 创建有范围的动作, 参见 <a href="https://cn.mobx.js.org/refguide/action.html" target="_blank" rel="noopener"><code>action</code></a></li>
</ul>
<p>可以使用 <em>@decorator</em> 语法来应用这些装饰器:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;observable, action&#125; <span class="keyword">from</span> <span class="string">'mobx'</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TaskStore</span> </span>&#123;</span><br><span class="line">    @observable.shallow tasks = []</span><br><span class="line">    @action addTask(task) &#123; <span class="comment">/* ... */</span> &#125;</span><br><span class="line">&#125;</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p>或者通过 <code>observable.object</code> / <code>observable.extendObservable</code> 或 <a href="https://cn.mobx.js.org/refguide/api.html#decorate" target="_blank" rel="noopener"><code>decorate()</code></a> 传入属性装饰器。 注意，装饰器总是“附着”在属性上的。 因此，即使分配了新值，它们仍将保持有效。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;observable, action&#125; <span class="keyword">from</span> <span class="string">'mobx'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> taskStore = observable(&#123;</span><br><span class="line">    tasks: [],</span><br><span class="line">    addTask(task) &#123; <span class="comment">/* ... */</span> &#125;</span><br><span class="line">&#125;, &#123;</span><br><span class="line">    tasks: observable.shallow,</span><br><span class="line">    addTask: action</span><br><span class="line">&#125;)</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><a href="https://cn.mobx.js.org/refguide/modifiers.html" target="_blank" rel="noopener">«详情»</a></p>
<p><code>decorate</code></p>
<p>用法: <code>decorate(object, decorators)</code></p>
<p>这是将可观察性<a href="https://cn.mobx.js.org/refguide/(#decorators)" target="_blank" rel="noopener">装饰器</a>应用于普通对象或类实例的简便方法。第二个参数是一个属性设置为某些装饰器的对象。</p>
<p>当无法使用 <em>@decorator</em> 语法或需要对可观察性进行更细粒度的控制时使用这个方法。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TodoList</span> </span>&#123;</span><br><span class="line">    todos = &#123;&#125;</span><br><span class="line">    <span class="keyword">get</span> unfinishedTodoCount() &#123;</span><br><span class="line">        <span class="keyword">return</span> values(<span class="keyword">this</span>.todos).filter(<span class="function"><span class="params">todo</span> =&gt;</span> !todo.finished).length</span><br><span class="line">    &#125;</span><br><span class="line">    addTodo() &#123;</span><br><span class="line">        <span class="keyword">const</span> t = <span class="keyword">new</span> Todo()</span><br><span class="line">        t.title = <span class="string">'Test_'</span> + <span class="built_in">Math</span>.random()</span><br><span class="line">        <span class="keyword">set</span>(this.todos, t.id, t)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">decorate(TodoList, &#123;</span><br><span class="line">    todos: observable,</span><br><span class="line">    unfinishedTodoCount: computed,</span><br><span class="line">    addTodo: action.bound</span><br><span class="line">&#125;)</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p>想要在单个属性上应用多个装饰器的话，你可以传入一个装饰器数组。多个装饰器应用的顺序是从从右至左。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; decorate, observable &#125; <span class="keyword">from</span> <span class="string">'mobx'</span></span><br><span class="line"><span class="keyword">import</span> &#123; serializable, primitive &#125; <span class="keyword">from</span> <span class="string">'serializr'</span></span><br><span class="line"><span class="keyword">import</span> persist <span class="keyword">from</span> <span class="string">'mobx-persist'</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Todo</span> </span>&#123;</span><br><span class="line">    id = <span class="built_in">Math</span>.random();</span><br><span class="line">    title = <span class="string">''</span>;</span><br><span class="line">    finished = <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">decorate(Todo, &#123;</span><br><span class="line">    title: [serializable(primitive), persist(<span class="string">'object'</span>), observable],</span><br><span class="line">    finished: [serializable(primitive), observable]</span><br><span class="line">&#125;)</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p>注意: 并非所有的装饰器都可以在一起组合，此功能只会尽力而为。一些装饰器会直接影响实例，并且可以“隐藏”其他那些只更改原型的装饰器的效果。</p>
<h3 id="Computed-values-计算值"><a href="#Computed-values-计算值" class="headerlink" title="Computed values(计算值)"></a>Computed values(计算值)</h3><p>用法:</p>
<ul>
<li><code>computed(() =&gt; expression)</code></li>
<li><code>computed(() =&gt; expression, (newValue) =&gt; void)</code></li>
<li><code>computed(() =&gt; expression, options)</code></li>
<li><code>@computed({equals: compareFn}) get classProperty() { return expression; }</code></li>
<li><code>@computed get classProperty() { return expression; }</code></li>
</ul>
<p>创建计算值，<code>expression</code> 不应该有任何副作用而只是返回一个值。 如果任何 <code>expression</code> 中使用的 observable 发生改变，它都会自动地重新计算，但前提是计算值被某些 <strong>reaction</strong> 使用了。</p>
<p>还有各种选项可以控制 <code>computed</code> 的行为。包括:</p>
<ul>
<li><strong><code>equals: (value, value) =&gt; boolean</code></strong> 用来重载默认检测规则的比较函数。 内置比较器有: <code>comparer.identity</code>, <code>comparer.default</code>, <code>comparer.structural</code></li>
<li><strong><code>requiresReaction: boolean</code></strong> 在重新计算衍生属性之前，等待追踪的 observables 值发生变化</li>
<li><strong><code>get: () =&gt; value)</code></strong> 重载计算属性的 getter</li>
<li><strong><code>set: (value) =&gt; void</code></strong> 重载计算属性的 setter</li>
<li><strong><code>keepAlive: boolean</code></strong> 设置为 true 以自动保持计算值活动，而不是在没有观察者时暂停。</li>
</ul>
<p><a href="https://cn.mobx.js.org/refguide/computed-decorator.html" target="_blank" rel="noopener">«详情»</a></p>
<h3 id="Actions-动作"><a href="#Actions-动作" class="headerlink" title="Actions(动作)"></a>Actions(动作)</h3><p>任何应用都有动作。动作是任何用来修改状态的东西。</p>
<p>使用MobX你可以在代码中显式地标记出动作所在的位置。 动作可以有助于更好的组织代码。 建议在任何更改 observable 或者有副作用的函数上使用动作。 结合开发者工具的话，动作还能提供非常有用的调试信息。 注意: 当启用<strong>严格模式</strong>时，需要强制使用 <code>action</code>，参见 <code>enforceActions</code>。</p>
<p><a href="https://cn.mobx.js.org/refguide/action.html" target="_blank" rel="noopener">«详情»</a></p>
<p>用法:</p>
<ul>
<li><code>action(fn)</code></li>
<li><code>action(name, fn)</code></li>
<li><code>@action classMethod</code></li>
<li><code>@action(name) classMethod</code></li>
<li><code>@action boundClassMethod = (args) =&gt; { body }</code></li>
<li><code>@action.bound boundClassMethod(args) { body }</code></li>
</ul>
<p>对于一次性动作，可以使用 <code>runInAction(name?, fn)</code> , 它是 <code>action(name, fn)()</code> 的语法糖.</p>
<p>Flow：</p>
<p>用法: <code>flow(function* (args) { })</code></p>
<p><code>flow()</code> 接收 generator 函数作为它唯一的输入</p>
<p>当处理<strong>异步动作</strong>时，回调中执行的代码不会被 <code>action</code> 包装。这意味着你修改的 observable state 无法通过 <a href="https://cn.mobx.js.org/refguide/api.html#configure" target="_blank" rel="noopener"><code>enforceActions</code></a> 检查。保留动作语义的简单方法是使用 flow 来包装异步函数。这将确保所有回调都会被 <code>action()</code> 包装。</p>
<p>注意，异步函数必须是 <em>generator</em> ，而且在内部只能 <em>yield</em> promises 。<code>flow</code> 会返回一个 promise ，需要的话可以使用 <code>cancel()</code> 进行撤销。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; configure &#125; <span class="keyword">from</span> <span class="string">'mobx'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 不允许在动作外部修改状态</span></span><br><span class="line">configure(&#123; <span class="attr">enforceActions</span>: <span class="literal">true</span> &#125;);</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Store</span> </span>&#123;</span><br><span class="line">    @observable githubProjects = [];</span><br><span class="line">    @observable state = <span class="string">"pending"</span>; <span class="comment">// "pending" / "done" / "error"</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    fetchProjects = flow(<span class="function"><span class="keyword">function</span>* <span class="title">fetchProjects</span>(<span class="params"></span>) </span>&#123; <span class="comment">// &lt;- 注意*号，这是生成器函数！</span></span><br><span class="line">        <span class="keyword">this</span>.githubProjects = [];</span><br><span class="line">        <span class="keyword">this</span>.state = <span class="string">"pending"</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> projects = <span class="keyword">yield</span> fetchGithubProjectsSomehow(); <span class="comment">// 用 yield 代替 await</span></span><br><span class="line">            <span class="keyword">const</span> filteredProjects = somePreprocessing(projects);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 异步代码自动会被 `action` 包装</span></span><br><span class="line">            <span class="keyword">this</span>.state = <span class="string">"done"</span>;</span><br><span class="line">            <span class="keyword">this</span>.githubProjects = filteredProjects;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">            <span class="keyword">this</span>.state = <span class="string">"error"</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><em>提示: 推荐为 generator 函数起个名称，此名称将出现在开发工具中</em></p>
<p><strong>Flows 可以撤销</strong></p>
<p>Flows 是可以取消的，这意味着调用返回的 promise 的 <code>cancel()</code> 方法。这会立即停止 generator ，但是 <code>finally</code> 子句仍会被处理。 返回的 promise 本身会使用 <code>FLOW_CANCELLED</code> 进行 reject 。</p>
<p><strong>Flows 支持异步迭代器</strong></p>
<p>Flows 支持异步迭代器，这意味着可以使用异步 generators :</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span>* <span class="title">someNumbers</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">yield</span> <span class="built_in">Promise</span>.resolve(<span class="number">1</span>)</span><br><span class="line">    <span class="keyword">yield</span> <span class="built_in">Promise</span>.resolve(<span class="number">2</span>)</span><br><span class="line">    <span class="keyword">yield</span> <span class="built_in">Promise</span>.resolve(<span class="number">3</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> count = mobx.flow(<span class="keyword">async</span> <span class="function"><span class="keyword">function</span>*(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 使用 await 来循环异步迭代器</span></span><br><span class="line">    <span class="keyword">for</span> <span class="keyword">await</span> (<span class="keyword">const</span> number <span class="keyword">of</span> someNumbers()) &#123;</span><br><span class="line">        total += number</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> total</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> res = <span class="keyword">await</span> count() <span class="comment">// 6</span></span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<h3 id="Reactions-反应-amp-Derivations-衍生"><a href="#Reactions-反应-amp-Derivations-衍生" class="headerlink" title="Reactions(反应) &amp; Derivations(衍生)"></a>Reactions(反应) &amp; Derivations(衍生)</h3><p><strong>计算值</strong> 是自动响应状态变化的<strong>值</strong>。 <strong>反应</strong> 是自动响应状态变化的<strong>副作用</strong>。 反应可以确保当相关状态发生变化时指定的副作用(主要是 I/O)可以自动地执行，比如打印日志、网络请求、等等。 使用反应最常见的场景是 React 组件的 <code>observer</code> 装饰器(参见下文)。</p>
<p><code>observer</code></p>
<p>可以用作包裹 React 组件的高阶组件。 在组件的 <code>render</code> 函数中的任何已使用的 observable 发生变化时，组件都会自动重新渲染。 注意 <code>observer</code> 是由 <code>&quot;mobx-react&quot;</code> 包提供的，而不是 <code>mobx</code> 本身。</p>
<p><a href="https://cn.mobx.js.org/refguide/observer-component.html" target="_blank" rel="noopener">«详情»</a></p>
<p>用法:</p>
<ul>
<li><code>observer(React.createClass({ ... }))</code></li>
<li><code>observer((props, context) =&gt; ReactElement)</code></li>
<li><code>observer(class MyComponent extends React.Component { ... })</code></li>
<li><code>@observer class MyComponent extends React.Component { ... }</code></li>
</ul>
<p><code>autorun</code></p>
<p>用法：<code>autorun(() =&gt; { sideEffect }, options)</code> 。<code>autorun</code> 负责运行所提供的 <code>sideEffect</code> 并追踪在<code>sideEffect</code>运行期间访问过的 <code>observable</code> 的状态。 将来如果有其中一个已使用的 observable 发生变化，同样的<code>sideEffect</code>会再运行一遍。 <code>autorun</code> 返回一个清理函数用来取消副作用。</p>
<p><a href="https://cn.mobx.js.org/refguide/autorun.html" target="_blank" rel="noopener">«详情»</a></p>
<p><strong>选项</strong></p>
<ul>
<li><strong><code>name?: string</code></strong>: 用于识别和调试的名称</li>
<li><strong><code>delay?: number</code></strong>: 使副作用延迟和防抖的时间。默认为 <code>0</code></li>
<li><strong><code>onError?: (error) =&gt; void</code></strong>: 如果 autorun 函数抛出异常，则触发错误处理函数</li>
<li><strong><code>scheduler?: (callback) =&gt; void</code></strong>: 设置自定义调度器以决定如何调度 autorun 函数的重新运行</li>
</ul>
<p><code>when</code></p>
<p>用法: <code>when(() =&gt; condition, () =&gt; { sideEffect }, options)</code> 。 <code>condition</code> 表达式会自动响应任何它所使用的 observable。 一旦表达式返回的是真值，副作用函数便会立即调用，但只会调用一次。</p>
<p><strong>注意:</strong> <em>副作用函数</em> (第二个参数) 其实是可选的。如果不提供副作用函数的话，将返回一个可取消的 promise (即具有 <code>cancle()</code> 方法的 promise)</p>
<p><code>when</code> 返回清理器以尽早地取消操作。</p>
<p>如果没有给 <code>when</code> 传递副作用函数的话，它将返回一个可以等待条件结束的 promise 。</p>
<p><a href="https://cn.mobx.js.org/refguide/when.html" target="_blank" rel="noopener">«详情»</a>.</p>
<p><strong>options</strong></p>
<ul>
<li><strong><code>name?: string</code></strong>: 用于识别和调试的名称</li>
<li><strong><code>onError?: (error) =&gt; void</code></strong>: 如果 <em>断言函数</em> 或 <em>副作用函数</em> 函数抛出异常，则触发错误处理函数</li>
<li><strong><code>timeout: number</code></strong> 以毫秒为单位的延迟，之后将触发 <code>onError</code> 处理函数，以通知在指定时间内未满足条件</li>
</ul>
<p><code>reaction</code></p>
<p>用法: <code>reaction(() =&gt; data, data =&gt; { sideEffect }, options)</code>. <code>reaction</code> 是 <code>autorun</code> 的变种，在如何追踪 observable 方面给予了更细粒度的控制。 它接收两个函数，第一个是追踪并返回数据，该数据用作第二个函数，也就是副作用的输入。 与 ‘autorun’ 不同的是副作用起初不会运行，并且在执行副作用时访问的任何 observable 都不会被追踪。 和 <code>autorunAsync</code> 一样，副作用是可以进行函数去抖的。</p>
<p><a href="https://cn.mobx.js.org/refguide/reaction.html" target="_blank" rel="noopener">«详情»</a></p>
<p><strong>options</strong></p>
<ul>
<li><strong><code>fireImmediately?: boolean</code></strong>: 在触发 <em>副作用函数</em> 之前等待变化。默认为 <code>false</code></li>
<li><strong><code>delay?: number</code></strong>: 使副作用延迟和防抖的时间。默认为 <code>0</code></li>
<li><strong><code>equals</code></strong>. 自定义相等函数来确定 expr 函数是否与之前的结果不同，再决定是否触发副作用。接收与 <code>computed</code> 的 equals 选项相同的选项</li>
<li>还接收 <a href="https://cn.mobx.js.org/refguide/api.html#autorun" target="_blank" rel="noopener"><code>autorun</code></a> 的所有选项</li>
</ul>
<p><code>onReactionError</code></p>
<p>用法: <code>onReactionError(handler: (error: any, derivation) =&gt; void)</code></p>
<p>此方法附加一个全局错误监听器，对于从 <em>reaction</em> 抛出的每个错误都会调用该错误监听器。 它可以用来监控或者测试。</p>
<hr>
<h2 id="实用工具"><a href="#实用工具" class="headerlink" title="实用工具"></a>实用工具</h2><p><em>有一些工具函数可以使得 observable 或者 计算值用起来更方便。 更多实用工具可以在 <a href="https://github.com/mobxjs/mobx-utils" target="_blank" rel="noopener">mobx-utils</a> 包中找到。</em></p>
<p><code>Provider</code> (<code>mobx-react</code> 包)</p>
<p>可以用来使用 React 的<code>context</code>机制来传递 store 给子组件。参见<a href="https://github.com/mobxjs/mobx-react#provider-experimental" target="_blank" rel="noopener"><code>mobx-react</code> 文档</a>。</p>
<p><code>inject</code> (<code>mobx-react</code> 包)</p>
<p>相当于<code>Provider</code> 的高阶组件。可以用来从 React 的<code>context</code>中挑选 store 作为 prop 传递给目标组件。用法:</p>
<ul>
<li><code>inject(&quot;store1&quot;, &quot;store2&quot;)(observer(MyComponent))</code></li>
<li><code>@inject(&quot;store1&quot;, &quot;store2&quot;) @observer MyComponent</code></li>
<li><code>@inject((stores, props, context) =&gt; props) @observer MyComponent</code></li>
<li><code>@observer([&quot;store1&quot;, &quot;store2&quot;]) MyComponent</code> is a shorthand for the the <code>@inject() @observer</code> combo.</li>
</ul>
<p><code>toJS</code></p>
<p>用法: <code>toJS(observableDataStructure, options?)</code> 。把 observable 数据结构转换成普通的 javascript 对象并忽略计算值。</p>
<p><code>options</code> 包括:</p>
<ul>
<li><strong><code>detectCycles: boolean</code></strong>: 检查 observalbe 数据结构中的循环引用。默认为 <code>true</code></li>
<li><strong><code>exportMapsAsObjects: boolean</code></strong>: 将 ES6 Map 作为普通对象导出。默认为 <code>true</code></li>
</ul>
<p><a href="https://cn.mobx.js.org/refguide/tojson.html" target="_blank" rel="noopener">«详情»</a>.</p>
<p><code>isObservable</code> 和 <code>isObservableProp</code></p>
<p>用法: <code>isObservable(thing)</code> 或 <code>isObservableProp(thing, property?)</code> 。如果给定的 thing，或者 thing 指定的 <code>property</code> 是 observable 的话，返回 true。 适用于所有的 observable、计算值和 reaction 的清理函数。</p>
<p><a href="https://cn.mobx.js.org/refguide/is-observable" target="_blank" rel="noopener">«详情»</a></p>
<p><code>isObservableObject|Array|Map</code> 和 <code>isBoxedObservable</code></p>
<p>用法: <code>isObservableObject(thing)</code>, <code>isObservableArray(thing)</code>, <code>isObservableMap(thing)</code>, <code>isBoxedObservable(thing)</code>。 如果类型匹配的话返回true。</p>
<p><code>isArrayLike</code></p>
<p>用法: <code>isArrayLike(thing)</code>。如果给定的 thing 是 javascript 数组或者 observable (MobX的)数组的话，返回 true。 这个方法更简便。 注意，observable 数组可以通过 <code>.slice()</code> 转变成 javascript 数组。</p>
<p><code>isAction</code></p>
<p>用法: <code>isAction(func)</code>。如果给定函数是用 <code>action</code> 方法包裹的或者是用 <code>@action</code> 装饰的话，返回 true。</p>
<p><code>isComputed</code> 或 <code>isComputedProp</code></p>
<p>用法: <code>isComputed(thing)</code> 或 <code>isComputedProp(thing, property?)</code> 。如果给定的 thing 是计算值或者 thing 指定的 <code>property</code> 是计算值的话，返回 true 。</p>
<p><code>intercept</code></p>
<p>用法: <code>intercept(object, property?, interceptor)</code>. 这个 API 可以在应用 observable 的API之前，拦截更改。对于验证、标准化和取消等操作十分有用。</p>
<p><a href="https://cn.mobx.js.org/refguide/observe.html" target="_blank" rel="noopener">«详情»</a></p>
<p><code>observe</code></p>
<p>用法: <code>observe(object, property?, listener, fireImmediately = false)</code> 这是一个底层API，用来观察一个单个的 observable 值。</p>
<p><a href="https://cn.mobx.js.org/refguide/observe.html" target="_blank" rel="noopener">«详情»</a></p>
<p><code>onBecomeObserved</code> 和 <code>onBecomeUnobserved</code></p>
<p>用法: <code>onBecomeObserved(observable, property?, listener: () =&gt; void): (() =&gt; void)</code> 和 <code>onBecomeUnobserved(observable, property?, listener: () =&gt; void): (() =&gt; void)</code> 这些函数都是与 MobX 的观察体系挂钩的，当 observables <em>开始</em> / <em>停止</em> 被观察时会收到通知。它可以用来执行一些延迟操作或网络资源获取。</p>
<p>返回值为 <em>清理函数</em>，用来卸载 <em>监听器</em> 。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">City</span> </span>&#123;</span><br><span class="line">    @observable location</span><br><span class="line">    @observable temperature</span><br><span class="line">    interval</span><br><span class="line"></span><br><span class="line">    <span class="keyword">constructor</span>(location) &#123;</span><br><span class="line">        <span class="keyword">this</span>.location = location</span><br><span class="line">        <span class="comment">// 只有当 temperature 实际使用了才开始获取数据!</span></span><br><span class="line">        onBecomeObserved(<span class="keyword">this</span>, <span class="string">'temperature'</span>, <span class="keyword">this</span>.resume)</span><br><span class="line">        onBecomeUnobserved(<span class="keyword">this</span>, <span class="string">'temperature'</span>, <span class="keyword">this</span>.suspend)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    resume = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        log(<span class="string">`Resuming <span class="subst">$&#123;<span class="keyword">this</span>.location&#125;</span>`</span>)</span><br><span class="line">        <span class="keyword">this</span>.interval = setInterval(<span class="function"><span class="params">()</span> =&gt;</span> <span class="keyword">this</span>.fetchTemperature(), <span class="number">5000</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    suspend = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        log(<span class="string">`Suspending <span class="subst">$&#123;<span class="keyword">this</span>.location&#125;</span>`</span>)</span><br><span class="line">        <span class="keyword">this</span>.temperature = <span class="literal">undefined</span></span><br><span class="line">        clearInterval(<span class="keyword">this</span>.interval)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @flow fetchTemperature = <span class="function"><span class="keyword">function</span>*(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="comment">// 数据获取逻辑</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><code>configure</code></p>
<p>用法: <code>configure(options)</code> 。 对活动的 MobX 实例进行全局行为设置。 使用它来改变 MobX 的整体表现。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; configure &#125; <span class="keyword">from</span> <span class="string">"mobx"</span>;</span><br><span class="line"></span><br><span class="line">configure(&#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;);</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><code>arrayBuffer: number</code></p>
<p>如果没有最大长度的话，则将可观察数组的默认创建长度增加至 <code>arrayBuffer</code> 。</p>
<p>可观察数组会在 <code>ObservableArray.prototype</code> 上惰性地创建数组项的 getters ，从第一项开始。 还会继续在数组中创建项，直到数组长度为 <code>arrayBuffer</code> (如果项不存在的话) 。 如果你清楚通用的最小数组长度，并且不想在主流程代码中创建这些 getters 的话，请使用 <code>arrayBuffer</code> 。 还可以参见 <code>observable</code> 。</p>
<p><code>computedRequiresReaction: boolean</code></p>
<p>禁止访问任何未观察的计算值。 如果想检查是否在没有响应式上下文中的使用计算属性的话，请使用它。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">configure(&#123; <span class="attr">computedRequiresReaction</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><code>disableErrorBoundaries: boolean</code></p>
<p>默认情况下，MobX 会捕获并重新抛出代码中发生的异常，从而确保某个异常中的反应 (reaction) 不会阻止其他可能无关的反应的预定执行。这意味着异常不会传播到原始代码中，因此将无法使用 try/catch 来捕获它们。</p>
<p>有时你可能想要捕获这些错误，例如在单元测试反应时。此时可以使用 <code>disableErrorBoundaries</code> 来禁用此行为。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">configure(&#123; <span class="attr">disableErrorBoundaries</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p>请注意，使用此配置时，MobX 并不会回复错误。出于这个原因，你可能需要在每个异常之后使用 <code>_resetGlobalState</code> 。示例如下:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">configure(&#123; <span class="attr">disableErrorBoundaries</span>: <span class="literal">true</span> &#125;)</span><br><span class="line"></span><br><span class="line">test(<span class="string">'Throw if age is negative'</span>, () =&gt; &#123;</span><br><span class="line">  expect(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> age = observable.box(<span class="number">10</span>)</span><br><span class="line">    autorun(<span class="function"><span class="params">()</span> =&gt;</span> &#123; <span class="keyword">if</span> (age.get() &lt; <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'Age should not be negative'</span>) &#125;)</span><br><span class="line">    age.set(<span class="number">-1</span>)</span><br><span class="line">  &#125;).toThrow()</span><br><span class="line">  _resetGlobalState() <span class="comment">// 每个异常过后都需要</span></span><br><span class="line">&#125;)</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<blockquote>
<p>在 MobX 4 之前，<code>_resetGlobalState</code> 名为 <code>extras.resetGlobalState</code> 。</p>
</blockquote>
<p><code>enforceActions</code></p>
<p>也被称为“严格模式”。</p>
<p>在严格模式下，不允许在 <a href="https://cn.mobx.js.org/refguide/action.html" target="_blank" rel="noopener"><code>action</code></a> 外更改任何状态。 可接收的值:</p>
<ul>
<li><code>&quot;never&quot;</code> (默认): 可以在任意地方修改状态</li>
<li><code>&quot;observed&quot;</code>: 在某处观察到的所有状态都需要通过动作进行更改。在正式应用中推荐此严格模式。</li>
<li><code>&quot;always&quot;</code>: 状态始终需要通过动作来更新(实际上还包括创建)。</li>
</ul>
<p><code>isolateGlobalState: boolean</code></p>
<p>当同一环境中有多个 MobX 实例时，将 MobX 的全局状态隔离。 当使用 MobX 的同时还使用了使用 MobX 的封装库时，这是非常有用的。 当在库中调用 <code>configure({isolateGlobalState：true})</code> 时，库内的响应性将保持独立。</p>
<p>使用此选项，如果多个 MobX 实例正在使用的话，内部状态是会共享的。优点就是两个实例的 observables 可以协同运行，缺点是 MobX 的版本必须匹配。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">configure(&#123; <span class="attr">isolateGlobalState</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><code>reactionScheduler: (f: () =&gt; void) =&gt; void</code></p>
<p>设置一个新函数，用来执行所有 MobX 的反应 (reactions) 。 默认情况下，<code>reactionScheduler</code> 只会运行反应 <code>f</code> 而没有其他任何行为。 这对于基本的调试或者减慢反应以使用应用的更新更加可视化来说是非常有用的。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">configure(&#123;</span><br><span class="line">    reactionScheduler: (f): <span class="function"><span class="params">void</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"Running an event after a delay:"</span>, f);</span><br><span class="line">        setTimeout(f, <span class="number">100</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<h2 id="直接操控-Observable"><a href="#直接操控-Observable" class="headerlink" title="直接操控 Observable"></a>直接操控 Observable</h2><p>现在有一个统一的工具 API 可以操控 observable 映射、对象和数组。这些 API 都是响应式的，这意味着如果使用 <code>set</code> 进行添加，使用 <code>values</code> 或 <code>keys</code> 进行迭代，即便是新属性的声明都可以被 MobX 检测到。</p>
<ul>
<li><strong><code>values(thing)</code></strong> 将集合中的所有值作为数组返回</li>
<li><strong><code>keys(thing)</code></strong> 将集合中的所有键作为数组返回</li>
<li><strong><code>entries(thing)</code></strong> 返回集合中的所有项的键值对数组</li>
<li><strong><code>set(thing, key, value)</code></strong> 或 <strong><code>set(thing, { key: value })</code></strong> 使用提供的键值对来更新给定的集合</li>
<li><strong><code>remove(thing, key)</code></strong> 从集合中移除指定的项。用于数组拼接</li>
<li><strong><code>has(thing, key)</code></strong> 如果集合中存在指定的 <em>observable</em> 属性就返回 true</li>
</ul>
<h2 id="开发工具"><a href="#开发工具" class="headerlink" title="开发工具"></a>开发工具</h2><p><em>如果你想在 MobX 的上层构建一些很酷的工具或者想检查 MobX 的内部状态的话，下列API可能会派上用场。</em></p>
<p><code>&quot;mobx-react-devtools&quot;</code> 包</p>
<p>mobx-react-devtools 是个功能强大的包，它帮助你调查 React 组件的性能和依赖。 还有基于 <code>spy</code> 的强大的日志功能。</p>
<p><a href="https://cn.mobx.js.org/best/devtools.html" target="_blank" rel="noopener">«详情»</a></p>
<p><code>trace</code></p>
<p>用法:</p>
<ul>
<li><code>trace(enterDebugger?)</code></li>
<li><code>trace(Reaction object / ComputedValue object / disposer function, enterDebugger?)</code></li>
<li><code>trace(object, computedValuePropertyName, enterDebugger?)</code></li>
</ul>
<p><code>trace</code> 是一个可以在计算值或 reaction 中使用的小工具。 如果启用了它，那么当值被无效时，它将开始记录，以及为什么。 如果 <code>enterDebugger</code> 设置为 true ，并且启用开发者工具的话，JavaScript 引擎会在触发时在此进行断点调试。</p>
<p><a href="https://cn.mobx.js.org/best/trace.html" target="_blank" rel="noopener">«trace»</a></p>
<p><code>spy</code></p>
<p>用法: <code>spy(listener)</code> 。 它类似于将一个 <code>observe</code> 监听器一次性附加到<strong>所有的</strong> observables 上，而且还负责正在运行的动作和计算的通知。 用于 <code>mobx-react-devtools</code> 。</p>
<p><a href="https://cn.mobx.js.org/refguide/spy.html" target="_blank" rel="noopener">«详情»</a></p>
<p><code>getAtom</code></p>
<p>用法: <code>getAtom(thing, property?)</code> 。 返回给定的 observable 对象、属性、reaction 等的背后作用的<code>Atom</code>。</p>
<p><code>getDebugName</code></p>
<p>用法: <code>getDebugName(thing, property?)</code> 。 返回 observable 对象、属性、reaction等(生成的)易读的调试名称。用于 <code>mobx-react-devtools</code> 的示例。</p>
<p><code>getDependencyTree</code></p>
<p>用法: <code>getDependencyTree(thing, property?)</code> 。 返回给定的 reaction / 计算 当前依赖的所有 observable 的树型结构。</p>
<p><code>getObserverTree</code></p>
<p>用法: <code>getObserverTree(thing, property?)</code> 。 返回正在观察给定的 observable 的所有 reaction / 计算的树型结构。</p>
<p><code>&quot;mobx-react&quot;</code> 开发钩子</p>
<p><code>mobx-react</code> 包提供了以下几个供 <code>mobx-react-devtools</code> 使用的附加API:</p>
<ul>
<li><code>trackComponents()</code>: 启用追踪功能,追踪使用了<code>observer</code>的 React 组件</li>
<li><code>renderReporter.on(callback)</code>: 使用 <code>observer</code> 的 React 组件每次渲染都会调用callback，并附带相关的时间信息等等</li>
<li><code>componentByNodeRegistery</code>: 使用ES6 WeakMap 将 DOMNode 映射到使用 <code>observer</code> 的 React 组件实例</li>
</ul>
<h2 id="内部函数"><a href="#内部函数" class="headerlink" title="内部函数"></a>内部函数</h2><p><em>以下方法都在 MobX 内部使用，在极少数情况下可能会派上用场。 但是通常 MobX 提供了更多的声明性替代方法来解决同样的问题。如果你尝试扩展 MobX 的话，它们可能会派上用场。</em></p>
<p><code>transaction</code></p>
<p><em>Transaction 是底层 API , 推荐使用 actions 来代替</em></p>
<p><code>transaction(worker: () =&gt; void)</code> 可以用来批量更新而不会通知任何观察者，直到事务结束。 <code>transaction</code> 接收一个无参的 <code>worker</code> 函数作为参数，并运行它。 到这个函数完成前都不会有任何观察者收到通知。 <code>transaction</code> 返回 <code>worker</code> 函数返回的任意值。 注意，<code>transaction</code> 的运行完全是同步的。 transactions 可以是嵌套的。只有当最外层的 <code>transaction</code> 完成后，等待中的 reactions 才会运行。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;observable, transaction, autorun&#125; <span class="keyword">from</span> <span class="string">"mobx"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> numbers = observable([]);</span><br><span class="line"></span><br><span class="line">autorun(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(numbers.length, <span class="string">"numbers!"</span>));</span><br><span class="line"><span class="comment">// 输出: '0 numbers!'</span></span><br><span class="line"></span><br><span class="line">transaction(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    transaction(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        numbers.push(<span class="number">1</span>);</span><br><span class="line">        numbers.push(<span class="number">2</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    numbers.push(<span class="number">3</span>);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 输出: '3 numbers!'</span></span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><code>untracked</code></p>
<p>untracked 允许你在没有观察者的情况下运行一段代码。 就像 <code>transaction</code> ，<code>untracked</code> 由 <code>(@)action</code> 自动应用，所以通常使用动作要比直接 <code>untracked</code> 有意义得多。 示例:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> person = observable(&#123;</span><br><span class="line">    firstName: <span class="string">"Michel"</span>,</span><br><span class="line">    lastName: <span class="string">"Weststrate"</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">autorun(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(</span><br><span class="line">        person.lastName,</span><br><span class="line">        <span class="string">","</span>,</span><br><span class="line">        <span class="comment">// 这个 untracked 代码块会在没有建立依赖的情况下返回 person 的 firstName</span></span><br><span class="line">        untracked(<span class="function"><span class="params">()</span> =&gt;</span> person.firstName)</span><br><span class="line">    );</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 输出: Weststrate, Michel</span></span><br><span class="line"></span><br><span class="line">person.firstName = <span class="string">"G.K."</span>;</span><br><span class="line"><span class="comment">// 不输出！</span></span><br><span class="line"></span><br><span class="line">person.lastName = <span class="string">"Chesterton"</span>;</span><br><span class="line"><span class="comment">// 输出: Chesterton, G.K.</span></span><br><span class="line">Copy</span><br></pre></td></tr></table></figure>

<p><code>createAtom</code></p>
<p>实用程序类，可用于创建你自己的 observable 数据结构，并将它们连接到 MobX。 在所有 observable 数据类型的内部使用。</p>

    </div>
    
    
    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
        <div class="reward-container">
  <div>坚持原创技术分享，您的支持将鼓励我继续创作！</div>
  <button onclick="var qr = document.getElementById('qr'); qr.style.display = (qr.style.display === 'none') ? 'block' : 'none';">
    打赏
  </button>
  <div id="qr" style="display: none;">
      
      <div style="display: inline-block;">
        <img src="/images/alipay.png" alt="Li Yudong 支付宝">
        <p>支付宝</p>
      </div>

  </div>
</div>

        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>Li Yudong
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="http://example.com/2021/11/30/%E7%9B%92%E9%A9%AC%E6%8A%80%E6%9C%AF%E6%A0%88%E5%88%9D%E5%AD%A6/Mobx%E5%85%A5%E9%97%A8/" title="Mobx入门">http://example.com/2021/11/30/盒马技术栈初学/Mobx入门/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

    
      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E5%85%AC%E5%8F%B8%E6%8A%80%E6%9C%AF%E6%A0%88/" rel="tag"># 公司技术栈</a>
          </div>
    
        

    
        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2021/11/30/%E7%9B%92%E9%A9%AC%E6%8A%80%E6%9C%AF%E6%A0%88%E5%88%9D%E5%AD%A6/Mobx-React/" rel="prev" title="Mobx-React">
      <i class="fa fa-chevron-left"></i> Mobx-React
    </a></div>
      <div class="post-nav-item">
    <a href="/2021/12/01/%E7%9B%92%E9%A9%AC%E6%8A%80%E6%9C%AF%E6%A0%88%E5%88%9D%E5%AD%A6/typeScript%E5%88%9D%E5%AD%A6/" rel="next" title="typeScript初学">
      typeScript初学 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Mobx"><span class="nav-number">1.</span> <span class="nav-text">Mobx</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#核心概念"><span class="nav-number">1.1.</span> <span class="nav-text">核心概念</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Observable-state"><span class="nav-number">1.1.1.</span> <span class="nav-text">Observable state</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Computed-values"><span class="nav-number">1.1.2.</span> <span class="nav-text">Computed values</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Reactions"><span class="nav-number">1.1.3.</span> <span class="nav-text">Reactions</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#React-组件"><span class="nav-number">1.1.3.1.</span> <span class="nav-text">React 组件</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#自定义-reactions"><span class="nav-number">1.1.3.2.</span> <span class="nav-text">自定义 reactions</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Actions"><span class="nav-number">1.1.4.</span> <span class="nav-text">Actions</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#简单可扩展"><span class="nav-number">1.1.5.</span> <span class="nav-text">简单可扩展</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Mobx要点"><span class="nav-number">1.2.</span> <span class="nav-text">Mobx要点</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#步骤"><span class="nav-number">1.2.1.</span> <span class="nav-text">步骤</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#概念与原则"><span class="nav-number">1.2.2.</span> <span class="nav-text">概念与原则</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#概念"><span class="nav-number">1.2.2.1.</span> <span class="nav-text">概念</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#原则"><span class="nav-number">1.2.2.2.</span> <span class="nav-text">原则</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实例"><span class="nav-number">1.2.2.3.</span> <span class="nav-text">实例</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#API"><span class="nav-number">2.</span> <span class="nav-text">API</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#核心API"><span class="nav-number">2.1.</span> <span class="nav-text">核心API</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#创建-observables"><span class="nav-number">2.1.1.</span> <span class="nav-text">创建 observables</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#装饰器-Decorators"><span class="nav-number">2.1.2.</span> <span class="nav-text">装饰器(Decorators)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Computed-values-计算值"><span class="nav-number">2.1.3.</span> <span class="nav-text">Computed values(计算值)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Actions-动作"><span class="nav-number">2.1.4.</span> <span class="nav-text">Actions(动作)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Reactions-反应-amp-Derivations-衍生"><span class="nav-number">2.1.5.</span> <span class="nav-text">Reactions(反应) &amp; Derivations(衍生)</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#实用工具"><span class="nav-number">2.2.</span> <span class="nav-text">实用工具</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#直接操控-Observable"><span class="nav-number">2.3.</span> <span class="nav-text">直接操控 Observable</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#开发工具"><span class="nav-number">2.4.</span> <span class="nav-text">开发工具</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#内部函数"><span class="nav-number">2.5.</span> <span class="nav-text">内部函数</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Li Yudong"
      src="/images/author.jpg">
  <p class="site-author-name" itemprop="name">Li Yudong</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">95</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">14</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">18</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/tiarmor1" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;tiarmor1" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:1157019137@qq.com" title="E-Mail → mailto:1157019137@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 2020 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Li Yudong</span>
</div>

        








      </div>
    </footer>
  </div>

  
  
  <script color='0,0,0' opacity='0.5' zIndex='-1' count='150' src="/lib1/canvas-nest/canvas-nest.min.js"></script>
  <script src="/lib1/anime.min.js"></script>
  <script src="/lib1/velocity/velocity.min.js"></script>
  <script src="/lib1/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  

  
   <canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas> 
   <script type="text/javascript" src="//cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script> 
   <script type="text/javascript" src="/js/fireworks.js"></script>
  
</body>
</html>

